/*
 * fs_dev.c - Mokri
 * Contributors: xMine
 * (Any new Contributor may add himself/herself to the list)
 * Changes and fixes to be made:
 * Source:
 */

#include "fs_dev.h"

struct dev_struct *dev_first_handle = NULL;
struct dev_struct *dev_last_handle = NULL;
int dev_cur = 0;
char dev_nr;

int dev_add_handle (struct dev_struct *handle) {
	handle->handle = dev_cur;
	dev_cur++;

	if (dev_first_handle == NULL) {
		dev_first_handle = handle;
		dev_last_handle = handle;
		handle->next = NULL;
	} else {
		dev_last_handle->next = handle;
		dev_last_handle = handle;
		handle->next = NULL;
	}

	//printf ("dev_add_handle: %i\n", dev_cur-1);

	return dev_cur - 1;
}

void dev_del_handle (int handle_num) {
	struct dev_struct *ptr = dev_first_handle;

	if (ptr == NULL) {
		return;
	}

	if (ptr->next == NULL) { // Einziger offener Handle?
		free (ptr);
		dev_first_handle = dev_last_handle = NULL;
	}

	while (ptr != NULL) { // Handle suchen
		if (ptr->next->handle == handle_num) {
			struct dev_struct *tmp = ptr->next;
			ptr->next = tmp->next;
			if (tmp == dev_last_handle) {
				dev_last_handle = ptr;
			}
			free (tmp);
			break;
		}

		ptr = ptr->next;
	}
}

struct dev_struct *dev_get_handle (int handle_num) {
	struct dev_struct *ptr = dev_first_handle;

	while (ptr != NULL) {
		if (ptr->handle == handle_num) {
			return ptr;
		}

		ptr = ptr->next;
	}

	return NULL;
}

BOOL dev_init (char nr) {
	dev_nr = nr;

	// /dev Ordner erstellen
	struct fs_entry *dev = fs_add_node ("dev", FS_FLAG_FOLDER, NULL, nr);

	if (dev == NULL) {
		kernel_panic ("Konnte nicht /dev erstellen!");
	}

	fs_add_node ("stdout", 0x0, dev, nr); // /dev/stdout
	fs_add_node ("stdin", 0x0, dev, nr);  // /dev/stdin

	return TRUE;
}

BOOL dev_deinit () {
	//print ("[Stoppe dev FS ");

	//print ("OK]");
	return TRUE;
}

FILE *dev_open (const char *path, struct fs_entry *entry, const char *params) {
	//printf ("FILE *dev_open (%s, , %s);\n", path, params);

	if (_strcmp (path, "/dev/stdout")) {
		struct dev_struct *h = (struct dev_struct *) malloc (sizeof (struct dev_struct));
		FILE *f = (FILE*) malloc (sizeof (FILE));
		h->filelen = 1;
		strcpy (h->path, "p");
		int num = dev_add_handle (h);
		f->driver = dev_nr;
		f->fpos = 0;
		f->handle = num;
		f->access = FS_ACC_WRITE;

		return f;
	}

	if (_strcmp (path, "/dev/stdin")) {
		struct dev_struct *h = (struct dev_struct *) malloc (sizeof (struct dev_struct));
		FILE *f = (FILE*) malloc (sizeof (FILE));
		h->filelen = 1;
		strcpy (h->path, "i");
		int num = dev_add_handle (h);
		f->driver = dev_nr;
		f->fpos = 0;
		f->handle = num;
		f->access = FS_ACC_READ;

		return f;
	}

	//printf ("dev_open ERROR: %s nicht gefunden\n", path);

	return NULL;
}

size_t dev_read (FILE *handle, char *buffer, size_t bytes) {
	struct dev_struct *h = dev_get_handle (handle->handle);

	if (h == NULL) {
		return FS_ERR_EOF;
	}

	if (h->path[0] == 'i') {
		gets (buffer);
		return strlen(buffer);
	}

	return FS_ERR_EOF;
}

size_t dev_write (FILE *handle, void *buffer, size_t bytes) {
	struct dev_struct *h = dev_get_handle (handle->handle);

	if (h == NULL) {
		return FS_ERR_EOF;
	}

	if (h->path[0] == 'p') {
		print (buffer);
		return bytes;
	}

	return FS_ERR_EOF;
}

int dev_close (FILE *handle) {
	dev_del_handle (handle->handle);
	return FS_ERR_SUCCESS;
}
